import { Injectable } from '@nestjs/common';
import { Bet, Tower } from '@prisma/client';
import { xorWith } from 'lodash';
import { PrismaService } from 'src/prisma/prisma.service';
import { calcAngle, calcHiFromTA, calcTBFromTA } from 'src/util/ljMath';

@Injectable()
export class CalculatePowerTowerService {
  /**
   * ! lstTA--区段张力侧杆塔轴向张力TA的集合
   * ! lstHi--区段内水平张力集合
   * ! towers--铁塔合集
   * ! bets--区段合集
   * ! TT--张力整定值
   * ! w--导线/牵引绳自重比载
   * ! w0--导引绳/牵引绳自重比载
   * ! e--摩擦系数
   * ! m--导线展放数量
   */
  private lstTA = [];
  private lstHi = [];
  private towers = [];
  private bets = [];
  private TT = 0;
  private w = 0;
  private w0 = 0;
  private e = 0;
  private m = 1;

  constructor(private readonly prisma: PrismaService) {}

  async calculate(config: Record<string, any>, TT: number) {
    const { zoneId, configId } = config;

    const zone = await this.prisma.zone.findFirst({
      where: { id: +zoneId },
      include: {
        bets: true,
        towers: true,
      },
    });
    const { towers: lst_tower, bets: lst_bet } = zone;
    this.towers = lst_tower;
    this.bets = lst_bet;

    const { num, e, DaoWire, QianWire } =
      await this.prisma.calcPowerConfig.findFirst({
        where: { id: +configId },
        include: {
          DaoWire: true,
          QianWire: true,
        },
      });
    this.TT = TT;
    this.m = num;
    this.e = e;
    this.w = DaoWire.wireWeight;
    this.w0 = QianWire.wireWeight;

    /**
     * !  i--记录走板所到的塔位编号
     **/
    for (let i = 0; i < this.towers.length; i++) {
      this.calcSigleTP(i);
      await this.prisma.calcPowerTower.create({
        data: {
          towerId: this.towers[i].id,
          configId: +configId,
          Hi: JSON.stringify(this.lstHi),
          Tp: JSON.stringify(this.lstTA),
        },
      });
    }
  }

  // 计算走板到达i#杆塔牵引力
  calcSigleTP(i: number) {
    // 张力机轴向张力
    let TA = this.TT;
    this.lstTA = [TA];
    this.lstHi = [];
    // 可采用递归方法进行简化区段张力侧杆塔轴向张力集合计算 TA
    this.calcTAByRecursion(0, i, TA);
    // console.log(this.lstTA);
  }

  // 采用递归计算TA
  calcTAByRecursion(n: number, i: number, T: number) {
    // 如果 n > 区段数量就退出
    if (n >= this.bets.length) return;

    const [tn1, tn2] = this.bets[n].btName.split('--');
    const t1 = this.towers.find((t) => t.tName === tn1);
    const t2 = this.towers.find((t) => t.tName === tn2);

    const h = t2.altitude - t1.altitude;
    const angle = calcAngle(h, this.bets[n].btSpan);
    const l = this.bets[n].btSpan;

    // i -- 记录走板所到的塔位编号
    // n -- 记录目前计算的区段 同时也表示区段张力侧塔位下标
    let TB = 0;
    let Hi = 0;
    if (n + 1 <= i) {
      // 如果 n < i,表示计算塔位 n# 在 i# 张力侧，所在区段的绳索都是牵引绳或者导线
      // 如果 n = i，表示在 n# 张力侧绳索是牵引绳或者导线，牵引侧绳索是导引绳
      TB = calcTBFromTA(T, this.w, this.m, h, angle);
      Hi = calcHiFromTA(this.w, h, l, T, angle); // 水平张力
    } else {
      TB = calcTBFromTA(T, this.w0, 1, h, angle);
      Hi = calcHiFromTA(this.w0, h, l, T, angle); // 水平张力
    }

    // 下一区段张力侧塔位的TA
    const TA = TB * this.e;

    this.lstTA.push(TA);
    this.lstHi.push(Hi);

    return this.calcTAByRecursion(n + 1, i, TA);
  }

  async findAll(args: Record<string, any>) {
    const { configId } = args;
    return await this.prisma.calcPowerTower.findMany({
      where: { configId: +configId },
      include: {
        tower: true,
      },
    });
  }
}
